package model.rotations;

import model.cubos.Adesivo;
import model.cubos.CuboMagico;
import model.matrizes.MatrizBidimensional;

/**
 * Esta classe possui as possíveis rotações do {@link CuboMagico}.
 * 
 * @author Joeffison Silverio de Andrade, 21011853, joeffisonsa@gmail.com
 * @version 1.0
 * @since 12/11/11 08:28
 */
public class RotationsImpl implements Rotations
{

    @Override
    public void U(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();

	// Todos os cubos tem apenas 4 cores.
	Adesivo[] linha_0 = cube[0][0];
	Adesivo[] linha_1 = cube[1][0];
	Adesivo[] linha_2 = cube[2][0];
	Adesivo[] linha_3 = cube[3][0];
	// Adesivo[][] linhas_do_topo = cube[4]; // É o próprio topo.

	/* Trocando as linhas. */
	cube[0][0] = linha_1;
	cube[1][0] = linha_2;
	cube[2][0] = linha_3;
	cube[3][0] = linha_0;

	MatrizBidimensional.transposta(cube[4]); // Finalmente aplicando conceitos que pensamos não ter aplicações...
						 // xP
	MatrizBidimensional.espelharColunas(cube[4]);

    }

    @Override
    public void U_(CuboMagico cubo)
    {
	U(cubo);
	U(cubo);
	U(cubo);
    }

    @Override
    public void U2(CuboMagico cubo)
    {
	U(cubo);
	U(cubo);
    }

    @Override
    public void D(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();

	// Todos os cubos tem apenas 4 cores.
	Adesivo[] linha_0 = cube[0][cube[0].length - 1]; // Últimas linhas do cubo.
	Adesivo[] linha_1 = cube[1][cube[0].length - 1];
	Adesivo[] linha_2 = cube[2][cube[0].length - 1];
	Adesivo[] linha_3 = cube[3][cube[0].length - 1];

	// Adesivo[][] linhas_do_topo = cube[4]; // É o próprio topo.

	/* Trocando as linhas. */
	cube[0][cube[0].length - 1] = linha_3;
	cube[1][cube[0].length - 1] = linha_0;
	cube[2][cube[0].length - 1] = linha_1;
	cube[3][cube[0].length - 1] = linha_2;

	MatrizBidimensional.transposta(cube[5]);
	MatrizBidimensional.espelharColunas(cube[5]);
    }

    @Override
    public void D_(CuboMagico cubo)
    {
	D(cubo);
	D(cubo);
	D(cubo);
    }

    @Override
    public void D2(CuboMagico cubo)
    {
	D(cubo);
	D(cubo);
    }

    @Override
    public void F(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	int[] interacaoCoresColunas = { 1, 3 };
	Adesivo[][] colunas = new Adesivo[2][dim];
	Adesivo[][] linhas = new Adesivo[2][dim];
	for (int i = 0; i < interacaoCoresColunas.length; i++)
	{
	    for (int j = 0; j < dim; j++)
	    {
		colunas[i][j] = cube[interacaoCoresColunas[i]][j][(i == 0 ? 0 : 2)];
	    }
	}
	linhas[0] = cube[4][2];
	linhas[1] = cube[5][0];

	cube[1][0][0] = linhas[0][0];
	cube[1][1][0] = linhas[0][1];
	cube[1][2][0] = linhas[0][2];

	cube[3][0][2] = linhas[1][0];
	cube[3][1][2] = linhas[1][1];
	cube[3][2][2] = linhas[1][2];

	cube[4][2][0] = colunas[1][2];
	cube[4][2][1] = colunas[1][1];
	cube[4][2][2] = colunas[1][0];

	cube[5][0][0] = colunas[0][2];
	cube[5][0][1] = colunas[0][1];
	cube[5][0][2] = colunas[0][0];

	MatrizBidimensional.transposta(cube[0]);
	MatrizBidimensional.espelharColunas(cube[0]);
    }

    @Override
    public void F_(CuboMagico cubo)
    {
	F(cubo);
	F(cubo);
	F(cubo);
    }

    @Override
    public void F2(CuboMagico cubo)
    {
	F(cubo);
	F(cubo);
    }

    @Override
    public void B(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	int[] interacaoCoresColunas = { 1, 3 };
	Adesivo[][] colunas = new Adesivo[2][dim];
	Adesivo[][] linhas = new Adesivo[2][dim];
	for (int i = 0; i < interacaoCoresColunas.length; i++)
	{
	    for (int j = 0; j < dim; j++)
	    {
		colunas[i][j] = cube[interacaoCoresColunas[i]][j][(i == 0 ? 2 : 0)];
	    }
	}
	linhas[0] = cube[4][0];
	linhas[1] = cube[5][2];

	cube[1][0][2] = linhas[1][2];
	cube[1][1][2] = linhas[1][1];
	cube[1][2][2] = linhas[1][0];

	cube[3][0][0] = linhas[0][2];
	cube[3][1][0] = linhas[0][1];
	cube[3][2][0] = linhas[0][0];

	cube[4][0] = colunas[0];

	cube[5][2] = colunas[1];

	MatrizBidimensional.transposta(cube[2]);
	MatrizBidimensional.espelharColunas(cube[2]);
    }

    @Override
    public void B_(CuboMagico cubo)
    {
	B(cubo);
	B(cubo);
	B(cubo);
    }

    @Override
    public void B2(CuboMagico cubo)
    {
	B(cubo);
	B(cubo);
    }

    @Override
    public void R(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	int[] interacaoCores = { 0, /* 2, */4, 5 };
	Adesivo[][] colunas = new Adesivo[4][dim];
	for (int i = 0; i < interacaoCores.length; i++)
	{
	    for (int j = 0; j < dim; j++)
	    {
		colunas[i][j] = cube[interacaoCores[i]][j][dim - 1];
	    }
	}
	for (int j = 0; j < dim; j++)
	{
	    colunas[colunas.length - 1][j] = cube[2][j][0];
	}

	cube[0][0][2] = colunas[2][0];
	cube[0][1][2] = colunas[2][1];
	cube[0][2][2] = colunas[2][2];

	cube[4][0][2] = colunas[0][0];
	cube[4][1][2] = colunas[0][1];
	cube[4][2][2] = colunas[0][2];

	cube[5][0][2] = colunas[3][2];
	cube[5][1][2] = colunas[3][1];
	cube[5][2][2] = colunas[3][0];

	cube[2][0][0] = colunas[1][2];
	cube[2][1][0] = colunas[1][1];
	cube[2][2][0] = colunas[1][0];

	MatrizBidimensional.transposta(cube[1]);
	MatrizBidimensional.espelharColunas(cube[1]);
    }

    @Override
    public void R_(CuboMagico cubo)
    {
	R(cubo);
	R(cubo);
	R(cubo);
    }

    @Override
    public void R2(CuboMagico cubo)
    {
	R(cubo);
	R(cubo);
    }

    @Override
    public void L(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	int[] interacaoCores = { 0, /* 2, */4, 5 };
	Adesivo[][] colunas = new Adesivo[4][dim];
	for (int i = 0; i < interacaoCores.length; i++)
	{
	    for (int j = 0; j < dim; j++)
	    {
		colunas[i][j] = cube[interacaoCores[i]][j][0];
	    }
	}
	for (int j = 0; j < dim; j++)
	{
	    colunas[colunas.length - 1][j] = cube[2][j][dim - 1];
	}

	cube[0][0][0] = colunas[1][0];
	cube[0][1][0] = colunas[1][1];
	cube[0][2][0] = colunas[1][2];

	cube[5][0][0] = colunas[0][0];
	cube[5][1][0] = colunas[0][1];
	cube[5][2][0] = colunas[0][2];

	cube[4][0][0] = colunas[3][2];
	cube[4][1][0] = colunas[3][1];
	cube[4][2][0] = colunas[3][0];

	cube[2][0][2] = colunas[2][2];
	cube[2][1][2] = colunas[2][1];
	cube[2][2][2] = colunas[2][0];

	MatrizBidimensional.transposta(cube[3]);
	MatrizBidimensional.espelharColunas(cube[3]);
    }

    @Override
    public void L_(CuboMagico cubo)
    {
	L(cubo);
	L(cubo);
	L(cubo);
    }

    @Override
    public void L2(CuboMagico cubo)
    {
	L(cubo);
	L(cubo);
    }

    @Override
    public void executa(CuboMagico cubo, String[] operacoes)
    {
	for (String oper : operacoes)
	{
	    if (oper.equals("U"))
	    {
		U(cubo);
	    }
	    else if (oper.equals("U_"))
	    {
		U_(cubo);
	    }
	    else if (oper.equals("U2"))
	    {
		U2(cubo);
	    }
	    else if (oper.equals("D"))
	    {
		D(cubo);
	    }
	    else if (oper.equals("D_"))
	    {
		D_(cubo);
	    }
	    else if (oper.equals("D2"))
	    {
		D2(cubo);
	    }
	    else if (oper.equals("F"))
	    {
		F(cubo);
	    }
	    else if (oper.equals("F_"))
	    {
		F_(cubo);
	    }
	    else if (oper.equals("F2"))
	    {
		F2(cubo);
	    }
	    else if (oper.equals("B"))
	    {
		B(cubo);
	    }
	    else if (oper.equals("B_"))
	    {
		B_(cubo);
	    }
	    else if (oper.equals("B2"))
	    {
		B2(cubo);
	    }
	    else if (oper.equals("R"))
	    {
		R(cubo);
	    }
	    else if (oper.equals("R_"))
	    {
		R_(cubo);
	    }
	    else if (oper.equals("R2"))
	    {
		R2(cubo);
	    }
	    else if (oper.equals("L"))
	    {
		L(cubo);
	    }
	    else if (oper.equals("L_"))
	    {
		L_(cubo);
	    }
	    else if (oper.equals("L2"))
	    {
		L2(cubo);
	    }
	    else if (oper.equals("Z"))
	    {
		Z(cubo);
	    }
	    else if (oper.equals("Z_"))
	    {
		Z_(cubo);
	    }
	    else if (oper.equals("Z2"))
	    {
		Z2(cubo);
	    }
	    else
	    {
	    }
	}
    }

    public void Z(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	int[] interacaoCores = { 1, 3 /* , 4, 5 */};
	Adesivo[][] colunas = new Adesivo[2][dim];
	Adesivo[][] linhas = new Adesivo[2][dim];
	for (int i = 0; i < interacaoCores.length; i++)
	{
	    for (int j = 0; j < dim; j++)
	    {
		colunas[i][j] = cube[interacaoCores[i]][j][1];
	    }
	}

	linhas[0] = cube[4][1];
	linhas[1] = cube[5][1];

	cube[1][0][1] = linhas[1][2];
	cube[1][1][1] = linhas[1][1];
	cube[1][2][1] = linhas[1][0];

	cube[3][0][1] = linhas[0][2];
	cube[3][1][1] = linhas[0][1];
	cube[3][2][1] = linhas[0][0];

	cube[4][1] = colunas[0];

	cube[5][1] = colunas[1];

	F_(cubo);
	B(cubo);
    }

    public void Z_(CuboMagico cubo)
    {
	Z(cubo);
	Z(cubo);
	Z(cubo);
    }

    public void Z2(CuboMagico cubo)
    {
	Z(cubo);
	Z(cubo);
    }

    public void X(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	int[] interacaoCores = { 0, 2, 4, 5 };
	Adesivo[][] colunas = new Adesivo[4][dim];
	for (int i = 0; i < interacaoCores.length; i++)
	{
	    for (int j = 0; j < dim; j++)
	    {
		colunas[i][j] = cube[interacaoCores[i]][j][1];
	    }
	}

	cube[0][0][1] = colunas[3][0];
	cube[0][1][1] = colunas[3][1];
	cube[0][2][1] = colunas[3][2];

	cube[2][0][1] = colunas[2][2];
	cube[2][1][1] = colunas[2][1];
	cube[2][2][1] = colunas[2][0];

	cube[4][0][1] = colunas[0][0];
	cube[4][1][1] = colunas[0][1];
	cube[4][2][1] = colunas[0][2];

	cube[5][0][1] = colunas[1][2];
	cube[5][1][1] = colunas[1][1];
	cube[5][2][1] = colunas[1][0];

	L_(cubo);
	R(cubo);
    }

    public void X_(CuboMagico cubo)
    {
	X(cubo);
	X(cubo);
	X(cubo);
    }

    public void X2(CuboMagico cubo)
    {
	X(cubo);
	X(cubo);
    }

    public void Y(CuboMagico cubo)
    {
	E_(cubo);
	D_(cubo);
	U(cubo);
    }

    public void E_(CuboMagico cubo)
    {
	Adesivo[][][] cube = cubo.getCubo();
	int dim = cube[0].length;
	Adesivo[][] linhas = new Adesivo[4][dim];
	for (int i = 0; i < 4; i++)
	{
	    linhas[i] = cube[i][1];
	}

	cube[0][1] = linhas[1];
	cube[1][1] = linhas[2];
	cube[2][1] = linhas[3];
	cube[3][1] = linhas[0];
    }

    public void E(CuboMagico cubo)
    {
	E_(cubo);
	E_(cubo);
	E_(cubo);
    }

    public void E2(CuboMagico cubo)
    {
	E_(cubo);
	E_(cubo);
    }

    public void Y_(CuboMagico cubo)
    {
	Y(cubo);
	Y(cubo);
	Y(cubo);
    }

    public void Y2(CuboMagico cubo)
    {
	Y(cubo);
	Y(cubo);
    }

}